﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using dpptask2.Exceptions;

namespace dpptask2.OptionClasses
{
    public abstract class optionAttribute : Attribute
    {
        public string[] alternatives = new string[0];

        public string command;
        
        public string description;
        
        public FieldInfo field;

        public bool choiceRequired = true;

        public abstract void parse(object argumentClass, CmdLineToken choiceToken, CmdLineToken parameterToken);

        protected string fieldFullName()
        {
            return string.Format("{0}.{1}", field.DeclaringType.Name, field.Name);
        }

        public virtual void check()
        {
            checkCommand();
            checkFieldType();
        }

        private void checkFieldType()
        {
            Type expectedType = this.typeAccepted();
            Type fieldType = field.FieldType;

            if (!expectedType.Equals(fieldType))
                throw new ParserException(string.Format("Wrong type at property {0} ({1} found, {2} expected)", fieldFullName(), fieldType.Name, expectedType.Name));
        }

        private void checkCommand()
        {
            if (this.command == null)
                throw new ParserException(string.Format("Property {0} hasn't command defined.", fieldFullName()));
        }

        protected string addSlashes(string cmd)
        {
            if (cmd == null)
            {
                return "<command not defined!>";
            }

            if (cmd.Length == 1)
                return ParserConsts.CHOICESTARTSHORT + cmd;
            else
                return ParserConsts.CHOICESTARTLONG + cmd;
        }

        protected Type getPureType(Type type)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(System.Nullable<>)))
            {
                var genericTypes = type.GetGenericArguments();
                if (genericTypes.Count() == 1)
                    return genericTypes.Single();
                else
                    throw new ParserException(string.Format("Cannot get pure type from type {0}", type.Name));
            }
            else
                return type;
        }


        public abstract string getUsageText(string command);

        public abstract Type typeAccepted();
    }

}
